package com.ticket.sass.provider.business.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ticket.sass.common.entity.provider.TenantEntity;
import com.ticket.sass.common.entity.provider.TenantWxaConfigEntity;
import com.ticket.sass.common.entity.tenant.*;
import com.ticket.sass.provider.business.TenantBusiness;
import com.ticket.sass.provider.config.AppConfig;
import com.ticket.sass.provider.dto.input.tenant.*;
import com.ticket.sass.provider.dto.output.tenant.TransactionOutput;
import com.ticket.sass.provider.dto.output.tenant.TenantListOutput;
import com.ticket.sass.provider.dto.output.tenant.ThemeConfigOutput;
import com.ticket.sass.provider.dto.output.tenant.WxaConfigOutput;
import com.ticket.sass.provider.service.LabModel;
import com.ticket.sass.provider.service.PageModel;
import com.ticket.sass.provider.service.impl.*;
import com.ticket.sass.provider.util.BCryptUtil;
import com.ticket.sass.provider.util.FileUtil;
import com.ticket.sass.provider.util.ModelUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.TypeToken;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author ywb
 * @date 2024-03-29 14:29
 */
@Slf4j
@Service
@AllArgsConstructor
public class TenantBusinessImpl implements TenantBusiness {
    final FileUtil fileUtil;
    final ModelUtil modelUtil;
    final TenantServiceImpl service;
    final TenantAdminServiceImpl adminService;
    final CinemaServiceImpl cinemaService;
    
    final TenantAccountServiceImpl accountsService;
    final ThemeConfigServiceImpl themeConfigService;
    final WxPayConfigServiceImpl wxPayConfigService;

    final TenantFundFlowServiceImpl tenantFundFlowsService;
    final TenantWxaConfigServiceImpl tenantWxaConfigService;


    
    @Override
    public PageModel<TenantListOutput> list(TenantListInput input) {
        IPage<TenantEntity> filmEntityIPage = service.iPage(input);
        
        // 转换租户列表对象为输出对象
        List<TenantListOutput> outputs = modelUtil.listToList(filmEntityIPage.getRecords(), new TypeToken<List<TenantListOutput>>(){}.getType());
        
        List<Long> tenantIds = outputs.stream().map(TenantListOutput::getId).collect(Collectors.toList());
        
        // 余额
        Map<Long, BigDecimal> balancesByTenantIds = accountsService.getBalancesByTenantIds(tenantIds);
        
        // 影院关联关系
        Map<Long, List<CinemaEntity>> cinemasByTenantIds = cinemaService.getCinemasByTenantIds(tenantIds);
        
        Map<Long, String> dataByTenant = themeConfigService.getDataByTenant(tenantIds);
        
        Map<Long, TenantWxaConfigEntity> configsByTenantIds = tenantWxaConfigService.getConfigsByTenantIds(tenantIds);
        
        
        outputs.forEach(output -> {
            // 填充影院关联信息
            List<CinemaEntity> tenantCinemaMapEntities = cinemasByTenantIds.get(output.getId());
            
            if (tenantCinemaMapEntities != null) {
                output.setCinemas(tenantCinemaMapEntities.stream().map(o-> new LabModel(o.getId(), o.getName())).collect(Collectors.toList()));
            }
            
            output.setBalance(balancesByTenantIds.getOrDefault(output.getId(), new BigDecimal("0.0")));
            
            output.setThemeConfig(ThemeConfigOutput.fromJson(dataByTenant.get(output.getId())));
            
            output.setWxaConfig(new WxaConfigOutput(configsByTenantIds.get(output.getId())));
        });
        
        
        // 返回分页模型对象，假设总记录数为租户列表的大小
        return new PageModel<>(filmEntityIPage.getTotal(), outputs);
    }
    
    @Override
    public void add(TenantAddInput input) {
        // 将输入对象转换为租户实体对象并保存
        TenantEntity tenantEntity = modelUtil.mapToMap(input, TenantEntity.class);
        List<String> allKeys = service.getAllKeys();

        tenantEntity.setKey(generateRandomNumberString(allKeys));
        
        service.save(tenantEntity);
        
        // 模拟 生成 租户 key
        tenantEntity.setKey(String.valueOf(UUID.randomUUID().toString().hashCode()));
        
        themeConfigService.save(new ThemeConfigEntity(input.getThemeConfig().toString(), 0L, tenantEntity.getId()));
        WxaConfigInput wxaConfig = input.getWxaConfig();
        tenantWxaConfigService.save(new TenantWxaConfigEntity(wxaConfig.getAppid(), wxaConfig.getSecret(), tenantEntity.getId()));
        accountsService.save(new TenantAccountEntity(new BigDecimal("0.0"), tenantEntity.getId()));
        
        AdminEntity admin = modelUtil.mapToMap(input.getAdminConfig(), AdminEntity.class);
        admin.setPassword(new BCryptUtil(AppConfig.PWD_SECRET).encrypt(admin.getPassword()));
        admin.setEnable(Boolean.TRUE);
        admin.setTenantId(tenantEntity.getId());
        
        adminService.save(admin);
    }
    
    @Override
    public void upd(TenantUpdInput input) {
        // 将输入对象转换为租户实体对象并更新
        TenantEntity tenantEntity = modelUtil.mapToMap(input, TenantEntity.class);
        service.updateById(tenantEntity);
        
        themeConfigService.saveOrUpdateThemeConfig(0L, input.getThemeConfig().toString(), tenantEntity.getId());

        tenantWxaConfigService.saveOrUpdateWxaConfig(input.getWxaConfig().getAppid(), input.getWxaConfig().getSecret(), tenantEntity.getId());
    }
    
    @Override
    public PageModel<TransactionOutput> transactionInfo(TransactionInput input) {
    
        IPage<TenantFundFlowEntity> page = tenantFundFlowsService.iPage(input);
        
        List<TransactionOutput> outputs = modelUtil.listToList(
            page.getRecords(),
            new TypeToken<List<TransactionOutput>>(){}.getType()
        );

        return new PageModel<>(page.getTotal(), outputs);
    }
    
    public static String generateRandomNumberString(List<String> excludeSet) {
        String randomNumberString;
        do {
            randomNumberString = RandomUtil.randomNumbers(8);
        } while (excludeSet.contains(randomNumberString));
        return randomNumberString;
    }

}
